<!DOCTYPE html> 
<html lang="ja"> 
    <head> 
        <meta charset="utf-8"> 
        <meta name="viewport" content="width=device-width, user-scalable=no" />
        <meta name="apple-mobile-web-app-capable" content="yes" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>TM Lib</title>
        <script type="text/javascript" src="./../../src/tmlib.js"></script>
        <script>
            
            // 物理パラメータ
            var PHYSICS_PARAM = {};
            
            // グローバル変数
            var app = null;             // アプリケーション
            var visibleTrace = true;    // 軌跡表示
            var Circle = null;          // サークルクラス
            
            // スクリプトをロード
            TM.loadScript("app");
            TM.loadScript("app", "sound");
            
            // dat-giu をロード
            TM.addNamespace("dat-gui", "../../plugins/dat-gui");
            TM.loadDatGUI();
            
            // stats をロード
            TM.addNamespace("stats", "../../plugins/Stats");
            TM.loadStats();
            
            // メイン処理
            TM.main(function(){
                initParam();    // パラメータ初期化
                initGame()      // ゲーム初期化
                run();          // 実行
                
                TM.inform();    // インフォメーション
                
                // GUI
                if (window["dat"]) {
                    var gui = new dat.GUI();
                    
                    gui.add(window, "explode");
                    gui.add(window, "visibleTrace").setValue(true).onChange(function(){
                        app.scene.background = (visibleTrace) ? "rgba(0, 0, 0, 0.25)" : "rgba(0, 0, 0, 1)";
                    });
                    gui.add(PHYSICS_PARAM, "bounciness", 0, 1, 0.1);
                    gui.add(PHYSICS_PARAM, "friction", 0, 1, 0.01);
                    
                    // gravity フォルダ
                    var gradFolder = gui.addFolder('gravity');
                    gradFolder.add(PHYSICS_PARAM.gravity, "x", -2, 2, 0.1);
                    gradFolder.add(PHYSICS_PARAM.gravity, "y", -2, 2, 0.1);
                    gradFolder.open();
                }
            });
            
            /**
             * パラメータ初期化
             */
            var initParam = function()
            {
                // 物理パラメータ初期化
                PHYSICS_PARAM["bounciness"]    = 0.8;                          // 反発係数
                PHYSICS_PARAM["friction"]      = 0.99;                         // 摩擦係数
                PHYSICS_PARAM["gravity"]       = TM.Geom.Vector2(0, 0.8);      // 重力
                
                // 宇宙
                /*
                PHYSICS_PARAM["bounciness"]    = 1.0;                          // 反発係数
                PHYSICS_PARAM["friction"]      = 1.0;                          // 摩擦係数
                PHYSICS_PARAM["gravity"]       = TM.Math.Vector2(0, 0.0);      // 重力
                */
                
                // サウンド読み込み
                TM.$SoundManager.add("hit", "puu89." + TM.App.Sound.SUPPORT_EXT);
                
                // サークルクラス定義
                Circle = createCircleClass();
            };
            
            /**
             * ゲーム初期化
             */
            var initGame = function()
            {
                // アプリケーション生成
                app = TM.global.app = TM.App.CanvasApp();
                app.scene.background = "rgba(0, 0, 0, 0.25)";
                app.enableStats();
                
                for (var i=0; i<16; ++i) {
                    app.scene.addChild(Circle());
                }
                
                for (var i=0; i<app.scene.children.length-1; ++i) {
                    var target = app.scene.children[i];
                    for (var j=i+1; j<app.scene.children.length; ++j) {
                        var other = app.scene.children[j];
                        target.collisionList.push(other);
                    }
                }

            };
            
            /**
             * 実行
             */
            var run = function()
            {
                app.run();
            };
            
            /**
             * クラッシュ
             */
            var explode = function()
            {
                var app = TM.global.app;
                
                var children = app.scene.children;
                for (var i=0; i<children.length; ++i) {
                    var target = children[i];
                    target.explode();
                }
            };
            
            /**
             * サークルクラスを定義
             */
            var createCircleClass = function()
            {
                var Circle = TM.createClass({
                    superClass: TM.App.InteractiveGameElement,  // インタラクティブゲームエレメントを継承
                    
                    /**
                     * 初期化
                     */
                    init: function() {
                        this.superInit(TM.App.InteractiveGameElement);
                        
                        // 位置をセット
                        this.x = Math.floor(Math.random()*(window.innerWidth-100));
                        this.y = Math.floor(Math.random()*(window.innerHeight-100));
                        // 向きをセット
                        this.direction = TM.Geom.Vector2.random(0, 360, 25);
                        
                        // パラメータをセット
                        this.width  = 100;
                        this.height = 100;
                        this.radius = TM.isMobile ? TM.random(10, 15) : TM.random(25, 50);
                        this.m      = Math.PI*this.radius*this.radius;  // 面積 = 重さにする
                        
                        // 表示色設定
                        this.strokeStyle= "white";
                        this.colorAngle = TM.random(0, 360);
                        var g = TM.Graphics.Graphics();
                        var grad = g.context.createRadialGradient(0, 0, 0, 0, 0, this.radius);
                        grad.addColorStop(0.0, "hsla({color}, 65%, 50%, 0.0)".format({color: this.colorAngle}));
                        grad.addColorStop(0.95, "hsla({color}, 65%, 50%, 1.0)".format({color: this.colorAngle}));
                        grad.addColorStop(1.0, "hsla({color}, 65%, 50%, 0.0)".format({color: this.colorAngle}));
                        this.fillStyle  = grad;
                    },
                    
                    /**
                     * 描画
                     */
                    draw: function(graphics) {
                        graphics.setColorStyle(this.strokeStyle, this.fillStyle);
                        graphics.globalCompositeOperation = "lighter";
                        graphics.fillCircle(0, 0, this.radius);
                    },
                    
                    /**
                     * インタラクティブオブジェクト用更新関数
                     */
                    onEnterFrame: function() {
                        var app = TM.global.app;
                        
                        if (Circle.target == this) {
                            this.x = app.pointing.x;
                            this.y = app.pointing.y;
                            this.direction.x = app.pointing.dX;
                            this.direction.y = app.pointing.dY;
                            return ;
                        }
                        this.direction.mul( PHYSICS_PARAM.friction );
                        this.direction.add( PHYSICS_PARAM.gravity );
                        this.position.add(this.direction);
                        
                        var left    = this.radius;
                        var right   = window.innerWidth-this.radius;
                        var top     = this.radius;
                        var bottom  = window.innerHeight-this.radius;
                        if (this.x < left)  { this.x = left;    this.direction.x*=-1; }
                        if (this.x > right) { this.x = right;   this.direction.x*=-1; }
                        if (this.y < top)   { this.y = top;     this.direction.y*=-1; }
                        if (this.y > bottom){ this.y = bottom;  this.direction.y*=-1; }
                    },
                    
                    /**
                     * 衝突イベント時関数
                     */
                    onCollision: function(other)
                    {
                        // めり込んだ分を押し出す
                        var abVec = TM.Geom.Vector2.sub(other.position, this.position); // 自分から相手へのベクトル
                        var len = abVec.length();
                        if (len == 0) return ;
                        abVec.normalize();
                        
                        var distance = (this.radius + other.radius)-len;    // 自分と相手の距離
                        var sinkVec  = TM.Geom.Vector2.mul(abVec, distance/2);
                        this.position.sub(sinkVec);
                        other.position.add(sinkVec);
                        
                        // 向きベクトルを調整する
                        var V = TM.Geom.Vector2;
                        var m0 = this.m;
                        var m1 = other.m;
                        var e = PHYSICS_PARAM.bounciness;
                        
                        var ma = ( (m1 / (m0+m1))*(1+e) ) * V.dot(V.sub(other.direction,  this.direction), abVec);
                        var mb = ( (m0 / (m0+m1))*(1+e) ) * V.dot(V.sub( this.direction, other.direction), abVec);
                        
                        this.direction.add( V.mul(abVec, ma) );
                        other.direction.add( V.mul(abVec, mb) );
                        
                        // SE 再生
                        var vSubLen = this.direction.lengthSquared() + other.direction.lengthSquared();
                        if (TM.isMobile == false && vSubLen > 10*10) {
                            var hitSound = TM.$SoundManager.get("hit");
                            hitSound.volume = Math.min(1.0, vSubLen / 4000);
                            hitSound.play();
                        }
                    },
                    
                    onMouseOver: function() {
                        // this.fillStyle = "red";
                    },
                    
                    onMouseOut: function() {
                        // this.fillStyle = "white";
                    },
                    
                    onMouseDown: function() {
                        if (Circle.target == null) { Circle.target = this; }
                        this.direction.set(0, 0, 0);
                    },
                    onMouseUp: function() {
                        Circle.target = null;
                    },
                    
                    explode: function()
                    {
                        this.direction = TM.Geom.Vector2.random(0, 360, 50);
                    }
                });
                
                return Circle;
            };
            
        </script>

    </head>
    
    <body>
    </body>
</html>
